import axios from 'axios'
import cookie from 'vue-cookie'
import router from '@/router'
import qs from 'qs' // 字符串处理
import merge from 'lodash/merge' // 合并对象工具
import { Message, Loading } from 'element-ui' // 加载组件
import { clearLoginInfo } from '@/utils/index'
import { formatDate, YyMmDdToTimes } from '@/utils/time-util'
import { localStorageSet, localStorageGet } from '@/utils/storage-util'
import { refreshTokenApi } from '@/api/oauth'

let loading
let needLoadingRequestCount = 0
// 被挂起的请求数组
let subscribes = []
// 是否有请求在刷新token
localStorageSet('IS_REFRESH_TOKEN', false)
// 开始加载提示框
function startLoading() {
  loading = Loading.service({
    lock: true,
    text: '拼命加载中...',
    background: 'rgba(0, 0, 0, 0.2)'
  })
}
// 结束加载提示框
function endLoading() {
  if (!loading) return
  loading.close()
}
// 请求堆积开始加载提示框
export function showFullScreenLoading(config) {
  console.debug('showFullScreenLoading needLoadingRequestCount start >> ' + needLoadingRequestCount)
  if (needLoadingRequestCount === 0) {
    if (config.loading === true) {
      startLoading()
    }
  }
  needLoadingRequestCount++
  console.debug('showFullScreenLoading needLoadingRequestCount end >> ' + needLoadingRequestCount)
}
// 请求消减关闭加载提示框
export function tryHideFullScreenLoading() {
  console.debug('tryHideFullScreenLoading needLoadingRequestCount start >> ' + needLoadingRequestCount)
  if (needLoadingRequestCount <= 0) return
  needLoadingRequestCount--
  if (needLoadingRequestCount === 0) {
    endLoading()
  }
  console.debug('tryHideFullScreenLoading needLoadingRequestCount end >> ' + needLoadingRequestCount)
}
// push所有token过期后的请求到数组中
function subscribeTokenRefresh(i) {
  subscribes.push(i)
}
// 用新的token发起请求
function reloadSubscribe(i) {
  subscribes.map(cb => cb(i))
}
// 身份信息无效停止刷新token
function stopRefreshToken() {
  needLoadingRequestCount = 0
  endLoading()
  subscribes = []
}
// token是否过期
function isTokenExpired() {
  let expiredTime = cookie.get('expiredTime')
  let refreshToken = cookie.get('refreshToken')
  if (expiredTime && refreshToken) {
    let nowTime = new Date().getTime()
    return (expiredTime - nowTime) / 1000 < 6 * 60
  } else {
    // 不存在，需要重新登录
    stopRefreshToken()
  }
  return false
}
// token过期处理
function isRefreshToken(token, config) {
  if (!token) {
    let refreshToken = cookie.get('refreshToken')
    if (isTokenExpired()) {
      let isRefreshToken = localStorageGet('IS_REFRESH_TOKEN')
      if (!isRefreshToken || isRefreshToken === 'false') {
        localStorageSet('IS_REFRESH_TOKEN', true)
        refreshTokenApi(refreshToken).then(res => {
          localStorageSet('IS_REFRESH_TOKEN', false)
          if (res && res.code === 10000) {
            let data = res.data
            let expiredTime = formatDate(new Date().getTime() + (data.expiration * 1000), 'yyyy-MM-dd HH:mm:ss')
            cookie.set('accessToken', data.accessToken, {
              'expires': expiredTime
            })
            cookie.set('expiredTime', YyMmDdToTimes(expiredTime))
            reloadSubscribe(data.accessToken)
          } else {
            subscribes = []
            clearLoginInfo()
            directLogin()
          }
        }).catch(() => {
          subscribes = []
          clearLoginInfo()
          directLogin()
        })
      }
      let retry = new Promise((resolve, reject) => {
        subscribeTokenRefresh((newToken) => {
          config.headers['Authorization'] = newToken
          resolve(config)
        })
      })
      return retry
    }
  }
  showFullScreenLoading(config)
}
// 直接登录
function directLogin() {
  router.push({
    path: '/login',
    query: {
      redirectUrl: window.location.href.split('#')[1] || ''
    }
  })
}

const http = axios.create({
  baseURL: process.env.BASE_API,
  timeout: 1000 * 30, // 请求超时时间
  withCredentials: false, // 请求跨域时候不在请求中携带cookie
  headers: {
    'Content-Type': 'application/json;charset=utf-8'
  }
})
// 请求拦截
http.interceptors.request.use(config => {
  // 处理请求之前的配置
  const token = cookie.get('accessToken')
  config.headers['Authorization'] = token
  // 是否显示加载框
  if (config.loading === undefined) {
    config['loading'] = true
  }

  // 如果不需要token的接口直接返回
  if (config.url.startsWith('/oauth')) {
    return config
  }
  // 是否刷新token
  let retry = isRefreshToken(token, config)
  if (retry) return retry

  return config
}, error => {
  tryHideFullScreenLoading()
  console.log('error', error)
  Message.error({
    message: JSON.stringify(error)
  })
  // 请求失败的处理
  return Promise.reject(error)
})

// 响应拦截
let kictOutMsg = '您的账号在其他地方进行登录，如果不是本人操作，请修改密码！'
http.interceptors.response.use(res => {
  tryHideFullScreenLoading()
  let url = res.config.url
  let errorMsg = res.data.error
  if (res.status === 203) {
    clearLoginInfo()
    let isToast = true
    if (res.data.code === 10008) {
      if (cookie.get('accessToken')) {
        errorMsg = kictOutMsg
      } else {
        isToast = false
      }
    }
    if (isToast) {
      Message.error({
        message: errorMsg,
        duration: 3000
      })
    }
    if (url.lastIndexOf('login') === -1) {
      directLogin()
    }
    return new Promise()
  }
  return res.data
}, error => {
  let res = error.response
  let status = res.status
  let errorMsg = res.data.error
  let isLogin = false
  console.info('response status error >> ' + status)
  tryHideFullScreenLoading()
  if (status === 401) {
    isLogin = true
    console.info('response status error in 401')
    if (cookie.get('accessToken')) {
      errorMsg = kictOutMsg
    }
  } else if (status === 502) {
    errorMsg = '网络连接超时，请稍后再试！'
  }
  Message.error({
    message: errorMsg,
    duration: 3000
  })
  if (isLogin) {
    clearLoginInfo()
    directLogin()
  }
  return Promise.reject(error)
})

// 获取地址
http.url = (apiKey) => {
  let defaults = {
    'time': new Date().getTime()
  }
  let url = process.env.BASE_API + apiKey
  let randomTime = qs.stringify(defaults)
  randomTime = url.indexOf('?') === -1 ? '?' + randomTime : '&' + randomTime
  return url + randomTime
}
// get 请求参数处理
function queryParam (params = {}, openDefaultParams = true, isFormat = false) {
  let defaluts = {
    'time': new Date().getTime()
  }
  params = openDefaultParams ? merge(defaluts, params) : params
  if (isFormat) {
    return qs.stringify(params, { arrayFormat: 'repeat', allowDots: true })
  }
  return params
}
http.queryParam = queryParam
// post请求参数处理
function bodyData (data = {}, openDefaultdata = true, contentType = 'json') {
  let defaults = {
    'time': new Date().getTime()
  }
  data = openDefaultdata ? merge(defaults, data) : data
  return contentType === 'json' ? JSON.stringify(data) : qs.stringify(data)
}
http.bodyData = bodyData

export default http
